---
title: 'Creating New Agents'
section: 'advanced'
tags: ['customization', 'agent templates', 'agents']
order: 2
---

# Creating New Agents
Create specialized agents from scratch using TypeScript files in the `.agents/` directory.

**Types:**

  - **LLM-based** - Use prompts and language models
  - **Programmatic** - Use TypeScript generator functions with `handleSteps`

**Control Flow:**

  - `yield 'STEP'` - Run one LLM generation step
  - `yield 'STEP_ALL'` - Run until completion
  - `return` - End the agent's turn

**Accessing Context:**

  - `agentState` - Current agent state and message history
  - `prompt` - User's prompt to the agent
  - `params` - Additional parameters passed to the agent

## Basic Structure

Create a new TypeScript file in `.agents/` directory:

**.agents/my-custom-agent.ts**
```typescript
import { AgentDefinition } from './types/agent-definition'

const definition: AgentDefinition = {
  id: "my-custom-agent",
  version: "1.0.0",


  displayName: "My Custom Agent",
  spawnerPrompt: "Spawn this agent for specialized workflow tasks requiring custom logic",
  model: "anthropic/claude-4-sonnet-20250522",
  outputMode: "last_message",
  includeMessageHistory: true,
  toolNames: ["read_files", "write_file", "end_turn"],
  spawnableAgents: ["codebuff/researcher@0.0.1"],  // Use full name for built-in agents

  inputSchema: {
    prompt: {
      type: "string",
      description: "What documentation to create or update"
    }
  },

  systemPrompt: `You are a documentation specialist.`,
  instructionsPrompt: "Create comprehensive documentation based on the user's request. Research existing code and patterns first.",
  stepPrompt: "Continue working on the documentation. Use end_turn when complete."
}

export default definition
```

## Domain-Specific Examples

### API Documentation Agent

Specialized for documenting REST APIs and GraphQL schemas:

**.agents/api-documenter.ts**

```typescript
import { AgentDefinition } from './types/agent-definition'

const definition: AgentDefinition = {
  id: "api-documenter",
  version: "1.0.0",


  displayName: "API Documentation Specialist",
  spawnerPrompt: "Spawn this agent to create comprehensive API documentation with examples, schemas, and error codes",
  model: "anthropic/claude-4-sonnet-20250522",
  outputMode: "last_message",
  includeMessageHistory: true,

  toolNames: ["read_files", "code_search", "write_file", "spawn_agents", "end_turn"],
  spawnableAgents: ["codebuff/researcher@0.0.1"],  // Use full name for built-in agents

  inputSchema: {
    prompt: {
      type: "string",
      description: "What API endpoints or schemas to document"
    }
  },

  systemPrompt: "You are an API documentation specialist. Create clear, comprehensive documentation for REST APIs and GraphQL schemas with examples, request/response formats, and error codes.",
  instructionsPrompt: "Analyze the specified API endpoints and create detailed documentation including examples, parameters, and response schemas.",
  stepPrompt: "Continue documenting the API. Include practical examples and edge cases. Use end_turn when complete."
}

export default definition
```
### Database Migration Agent

Specialized for creating and reviewing database migrations:

**.agents/migration-specialist.ts**

```typescript
import { AgentDefinition } from './types/agent-definition'

const definition: AgentDefinition = {
  id: "migration-specialist",
  version: "1.0.0",


  displayName: "Database Migration Specialist",
  spawnerPrompt: "Spawn this agent to create safe, reversible database migrations with proper indexing and rollback procedures",
  model: "anthropic/claude-4-sonnet-20250522",
  outputMode: "last_message",
  includeMessageHistory: true,

  toolNames: [
    "read_files",
    "write_file",
    "code_search",
    "run_terminal_command",
    "end_turn"
  ],
  spawnableAgents: ["codebuff/reviewer@0.0.1"],

  systemPrompt: "You are a database migration specialist. Your goal is to create safe, reversible database migrations with proper indexing and rollback procedures.",
  instructionsPrompt: "Create a database migration for the requested schema changes. Ensure it's reversible and includes proper indexing.",
  stepPrompt: "Continue working on the migration. Test it if possible and spawn a reviewer to check for issues."
}

export default definition
```

## Programmatic Agents (Advanced)

**🎯 This is where Codebuff agents become truly powerful!** While LLM-based agents work well for many tasks, programmatic agents give you precise control over complex workflows, while still letting you tap into LLMs when you want them.

### Why Use Programmatic Agents?

- **Deterministic workflows** - Guarantee specific steps happen in order
- **Dynamic decision making** - Branch based on your own logic
- **Complex orchestration** - Coordinate multiple agents and tools with logic
- **State management** - Maintain state across multiple agent steps

### How It Works

Use TypeScript generator functions with the `handleSteps` field to control execution:

**.agents/code-analyzer.ts**
```typescript
import { AgentDefinition } from './types/agent-definition'

const definition: AgentDefinition = {
  id: "code-analyzer",
  displayName: "Code Analysis Expert",
  spawnerPrompt: "Spawn for deep code analysis and refactoring suggestions",
  model: "anthropic/claude-4-sonnet-20250522",

  toolNames: ["read_files", "code_search", "spawn_agents", "write_file"],
  spawnableAgents: ["codebuff/thinker@0.0.1", "codebuff/reviewer@0.0.1"],

  handleSteps: function* ({ agentState, prompt, params }) {
    // First, find relevant files
    const { toolResult: files } = yield {
      toolName: 'find_files',
      input: { query: prompt }
    }

    // Read the most important files
    if (files) {
      const filePaths = JSON.parse(files).slice(0, 5)
      yield {
        toolName: 'read_files',
        input: { paths: filePaths }
      }
    }

    // Spawn a thinker for deep analysis
    yield {
      toolName: 'spawn_agents',
      input: {
        agents: [{
          agent_type: 'thinker',
          prompt: `Analyze the code structure and suggest improvements for: ${prompt}`
        }]
      }
    }

    // Let the agent generate its response
    yield 'STEP_ALL'
  }
}

export default definition
```

### Key Concepts for Programmatic Agents

#### 1. Generator Function Basics

Your `handleSteps` function receives context and yields actions:

```typescript
handleSteps: function* ({ agentState, prompt, params }) {
  // agentState: Current conversation and agent state
  // prompt: What the user asked this agent to do
  // params: Additional parameters passed to the agent

  // Your logic here...
}
```

#### 2. Yielding Tool Calls

Execute tools and get their results:

```typescript
const { toolResult, toolError } = yield {
  toolName: 'read_files',
  input: { paths: ['file1.ts', 'file2.ts'] }
}

if (toolError) {
  // Handle error case
  console.error('Failed to read files:', toolError)
} else {
  // Use the result
  const fileContent = JSON.parse(toolResult)
}
```

#### 3. Control Flow Options

**Control Flow:**
- `yield 'STEP'` - Run one LLM generation step
- `yield 'STEP_ALL'` - Run until completion
- `return` - End the agent's turn

#### 4. Advanced Example: Conditional Workflow

```typescript
handleSteps: function* ({ agentState, prompt, params }) {
  // Step 1: Analyze the codebase
  const { toolResult: analysis } = yield {
    toolName: 'spawn_agents',
    input: {
      agents: [{
        agent_type: 'thinker',
        prompt: `Analyze: ${prompt}`
      }]
    }
  }

  // Step 2: Based on analysis, choose action
  if (analysis?.includes('refactor')) {
    // Get all files that need refactoring
    const { toolResult: files } = yield {
      toolName: 'find_files',
      input: { query: 'needs refactoring' }
    }

    // Step 3: Refactor each file
    for (const file of JSON.parse(files || '[]')) {
      yield {
        toolName: 'write_file',
        input: {
          path: file,
          instructions: 'Refactor for better performance',
          content: '// ... refactored code ...'
        }
      }
    }
  }

  // Step 4: Final review
  yield {
    toolName: 'spawn_agents',
    input: {
      agents: [{
        agent_type: 'reviewer',
        prompt: 'Review all changes'
      }]
    }
  }

  // Let the agent summarize
  yield 'STEP_ALL'
}
```

### When to Choose Programmatic vs LLM-based

**Use Programmatic (`handleSteps`) when:**
- You need guaranteed execution order
- Decisions depend on specific file contents
- Complex multi-step workflows with branching
- Integration with external systems
- Error recovery is critical

**Use LLM-based (prompts only) when:**
- Task is straightforward
- Agent needs creative freedom
- Natural language understanding is key
- Workflow is simple and linear
